<template>
  <div class="explore">
    <div class="cultivate" v-if="monster.name">
      你遇到了
      <span class="el-tag el-tag--danger" @click="openMonsterInfo" v-text="monster.name" />
      <div class="storyText">
        <div class="storyText-box">
          <el-scrollbar ref="scrollbar" always>
            <p class="fighting" v-if="isFighting" v-text="`${guashaRounds}回合 / 10回合`" />
            <p
              v-for="(item, index) in texts"
              :key="index"
              v-html="item"
              @click="openEquipmentInfo(openEquipItemInfo)"
            />
          </el-scrollbar>
        </div>
      </div>
      <div class="actions">
        <div class="action">
          <el-button class="item" @click="operate('startFight')" :disabled="isEnd">
            发起战斗
            <span class="shortcutKeys">(Q)</span>
          </el-button>
        </div>
        <div class="action">
          <el-button class="item" @click="operate('harvestPet')" :disabled="isCaptureFailed">
            收服对方
            <span class="shortcutKeys">(E)</span>
          </el-button>
        </div>
        <div class="action">
          <el-button class="item" @click="operate('runAway')" :disabled="isFailedRetreat">
            立马撤退
            <span class="shortcutKeys">(R)</span>
          </el-button>
        </div>
        <div class="action">
          <el-button class="item" @click="operate('explore')" :disabled="player.health <= 0" v-if="isEnd">
            继续探索
            <span class="shortcutKeys">(F)</span>
          </el-button>
        </div>
        <div class="action">
          <el-button class="item" @click="operate('goHome')" v-if="isEnd">
            回家疗伤
            <span class="shortcutKeys">(G)</span>
          </el-button>
        </div>
      </div>
    </div>
    <div class="cultivate error" v-else>
      <el-result icon="error" title="缺少对战信息" sub-title="请返回地图重新探索">
        <template #extra>
          <el-button :type="!player.dark ? 'primary' : ''" @click="router.push('/map')">返回地图</el-button>
        </template>
      </el-result>
    </div>
  </div>
</template>

<script setup>
  import { useRouter } from 'vue-router'
  import { ref, onMounted, onUnmounted } from 'vue'
  // 装备
  import equip from '@/plugins/equip'
  import { useMainStore } from '@/plugins/store'
  // 成就
  import achievement from '@/plugins/achievement'
  import {
    maxLv,
    levelNames,
    formatNumberToChineseUnit,
    genre,
    levels,
    gameNotifys,
    smoothScrollToBottom
  } from '@/plugins/game'
  import { ElMessageBox } from 'element-plus'

  const store = useMainStore()
  const router = useRouter()
  // 日志
  const texts = ref([])
  // 是否结束战斗
  const isEnd = ref(false)
  const player = ref(store.player)
  const mapData = ref(store.mapData)
  const mapScroll = ref(store.mapScroll)
  // 野怪信息
  const monster = ref(store.monster)
  const loading = ref(true)
  // 是否胜利
  const victory = ref(false)
  const timerIds = ref([])
  const isFighting = ref(false)
  // 回合数
  const guashaRounds = ref(10)
  // 撤退失败
  const isFailedRetreat = ref(false)
  // 收服失败
  const isCaptureFailed = ref(false)
  const openEquipItemInfo = ref({})
  const scrollbar = ref(null)

  // 玩家操作(绑定快捷键)
  const operate = oprName => {
    oprName = typeof oprName === 'string' ? oprName : oprName.key
    switch (oprName) {
      // 发起战斗
      case 'q':
      case 'startFight':
        if (!isEnd.value) startFight()
        break
      // 收服对方
      case 'e':
      case 'harvestPet':
        if (!isEnd.value && !isCaptureFailed.value) harvestPet(monster.value)
        break
      // 立马撤退
      case 'r':
      case 'runAway':
        if (!isEnd.value && !isFailedRetreat.value) runAway()
        break
      // 回家疗伤
      case 'g':
      case 'goHome':
        if (isEnd.value) goHome()
        break
      // 继续探索
      case 'f':
      case 'explore':
        if (isEnd.value) router.push('/map')
        return
      default:
        return
    }
  }

  // 回家疗伤
  const goHome = () => {
    mapData.value = { y: 0, x: 0, map: [] }
    router.push('/home')
    mapScroll.value = 0
  }

  // 怪物信息
  const openMonsterInfo = () => {
    const successRate = calculateCaptureRate()
    const newProperties = (100 - successRate) * 0.5
    ElMessageBox.alert('', monster.value.name, {
      center: true,
      message: `<div class="monsterinfo">
      <div class="monsterinfo-box">
        <p>境界: ${player.value.level == 0 ? levelNames(player.value.level + 1) : levelNames(player.value.level)}</p>
        <p>悟性: ${Math.floor(newProperties)}</p>
        <p>气血: ${formatNumberToChineseUnit(monster.value.health)}</p>
        <p>攻击: ${formatNumberToChineseUnit(monster.value.attack)}</p>
        <p>防御: ${formatNumberToChineseUnit(monster.value.defense)}</p>
        <p>闪避率: ${
          monster.value.dodge > 0 ? (monster.value.dodge * 100 > 100 ? 100 : (monster.value.dodge * 100).toFixed(2)) : 0
        }%</p>
        <p>暴击率: ${
          monster.value.critical > 0
            ? monster.value.critical * 100 > 100
              ? 100
              : (monster.value.critical * 100).toFixed(2)
            : 0
        }%</p>
        <p>收服率: ${successRate}%</p>
      </div>
    </div>`,
      confirmButtonText: '知道了',
      dangerouslyUseHTMLString: true
    }).catch(() => {})
  }

  // 开始攻击
  const startFight = () => {
    if (isEnd.value) return
    isEnd.value = true
    victory.value = false
    const zs = player.value.reincarnation * 10
    const time = zs >= 200 ? 100 : 300 - zs
    const timerId = setInterval(() => {
      fightMonster()
      const element = scrollbar.value?.wrapRef
      const observer = new MutationObserver(() => {
        smoothScrollToBottom(element)
      })
      observer.observe(element, {
        childList: true,
        subtree: true
      })
    }, time)
    timerIds.value.push(timerId)
  }

  // 停止攻击
  const stopFight = () => {
    timerIds.value.forEach(id => {
      clearInterval(id)
    })
    isEnd.value = true
    timerIds.value = []
    isFailedRetreat.value = true
    isCaptureFailed.value = true
  }

  // 攻击怪物
  const fightMonster = () => {
    isFighting.value = true
    if (monster.value.health <= 0) return
    // 野怪伤害计算
    const monsterAttack = monster.value.attack // 野怪攻击
    const playerDefense = player.value.defense // 玩家防御
    let monsterHarm = Math.max(0, Math.floor(monsterAttack - playerDefense)) // 野怪伤害
    monsterHarm = monsterHarm <= 1 ? 1 : monsterHarm // 伤害小于1时强制破防
    // 玩家伤害计算
    const playerAttack = player.value.attack // 玩家攻击
    const monsterDefense = monster.value.defense // 野怪防御
    let playerHarm = Math.max(0, Math.floor(playerAttack - monsterDefense)) // 玩家伤害基础值
    playerHarm = playerHarm <= 1 ? 1 : playerHarm // 伤害小于1时强制破防
    // 是否暴击
    let isMCritical = false,
      isCritical = false
    // 怪物是否闪避
    const isMHit = Math.random() > player.value.dodge
    // 玩家是否闪避
    const isPHit = Math.random() > monster.value.dodge
    // 检查野怪是否暴击
    if (Math.random() < monster.value.critical) {
      // 野怪暴击，伤害加倍
      monsterHarm *= 2
      // 野怪成功暴击
      isMCritical = true
    }
    // 检查玩家是否暴击
    if (Math.random() < player.value.critical) {
      // 玩家暴击，伤害加倍
      playerHarm *= 1.5
      // 玩家成功暴击
      isCritical = true
    }
    // 怪物没有闪避
    if (isMHit) player.value.health -= monsterHarm
    // 玩家没有闪避
    if (isPHit) monster.value.health -= playerHarm
    player.value.health = Math.max(0, player.value.health)
    monster.value.health = Math.max(0, monster.value.health)
    if (guashaRounds.value > 1) {
      // 扣除回合数
      guashaRounds.value--
      // 野怪气血小于等于0
      if (monster.value.health <= 0) {
        // 增加击杀数量
        player.value.taskNum++
        // 增加培养丹
        const reincarnation = player.value.reincarnation ? 1 + 1 * player.value.reincarnation : 1
        player.value.props.cultivateDan += reincarnation
        // 发送提示
        texts.value.push(`击败${monster.value.name}后你获得了${reincarnation}颗培养丹`)
        findTreasure(monster.value.name)
        stopFight()
      } else if (player.value.health <= 0) {
        texts.value.push('你因为太弱被击败了。')
        stopFight()
      } else {
        // 玩家
        texts.value.push(
          !isPHit
            ? `你攻击了${monster.value.name}，对方闪避了你的攻击，你未造成伤害，剩余${monster.value.health}气血。`
            : `你攻击了${monster.value.name}，${isCritical ? '触发暴击' : ''}造成了${playerHarm}点伤害，剩余${
                monster.value.health
              }气血。`
        )
        // 野怪
        texts.value.push(
          !isMHit
            ? `${monster.value.name}攻击了你，你闪避了对方的攻击，对方未造成伤害。`
            : `${monster.value.name}攻击了你，${isMCritical ? '触发暴击' : ''}造成了${monsterHarm}点伤害`
        )
      }
    } else {
      guashaRounds.value = 10
      texts.value.push(`回合结束, 你未战胜${monster.value.name}你输了。`)
      stopFight()
    }
  }

  // 逃跑
  const runAway = () => {
    guashaRounds.value--
    if (equip.getRandomInt(0, 1)) {
      isFailedRetreat.value = true
      texts.value.push('撤退失败，继续战斗。')
    } else {
      guashaRounds.value = 10
      router.push('/map')
      gameNotifys({ title: '提示', message: '你选择了撤退。' })
    }
  }

  // 发现道具
  const findTreasure = () => {
    let equipItem = {}
    let exp = Math.floor(player.value.maxCultivation / 100)
    exp = exp ? exp : 1
    // 如果总背包容量大于装备背包容量
    victory.value = true
    const randomInt = equip.getRandomInt(1, 4)
    // 神兵
    if (randomInt == 1) equipItem = equip.equip_Weapons(player.value.level)
    // 护甲
    else if (randomInt == 2) equipItem = equip.equip_Armors(player.value.level)
    // 灵宝
    else if (randomInt == 3) equipItem = equip.equip_Accessorys(player.value.level)
    // 法器
    else if (randomInt == 4) equipItem = equip.equip_Sutras(player.value.level)
    texts.value.push(
      `你击败${monster.value.name}后，发现了一个宝箱，打开后获得了<span class="el-tag el-tag--${equipItem.quality}">${
        levels[equipItem.quality]
      }${equipItem.name}(${genre[equipItem.type]})</span>`
    )
    openEquipItemInfo.value = equipItem
    // 如果装备背包当前容量大于等于背包总容量
    if (player.value.inventory.length >= player.value.backpackCapacity) {
      texts.value.push(`当前装备背包容量已满, 该装备自动丢弃, 转生可增加背包容量`)
    } else {
      // 玩家获得道具
      player.value.inventory.push(equipItem)
    }
    // 如果没有满级
    if (player.value.level < maxLv) {
      // 增加修为
      // 如果当前境界小于最高境界当前修为大于等于总修为
      if (player.value.level < maxLv) {
        if (player.value.cultivation >= player.value.maxCultivation) {
          // 如果玩家等级大于10并且击杀数低于当前等级
          if (player.value.level > 10 && player.value.level > player.value.taskNum) {
            texts.value.push(
              `当前境界修为已满, 你需要通过击败<span class="textColor">(${player.value.taskNum} / ${player.value.level})</span>个敌人证道突破`
            )
            return
          }
          // 清空已击杀敌人
          player.value.taskNum = 0
          // 增加境界
          player.value.level++
          // 增加点数
          player.value.points += 3
          // 更新气血
          player.value.health = player.value.maxHealth
          // 增加玩家总修为
          player.value.maxCultivation = Math.floor(100 * Math.pow(2, player.value.level))
          texts.value.push(`恭喜你突破了！当前境界：${levelNames(player.value.level)}`)
        } else {
          // 当前修为
          player.value.cultivation += exp
        }
      } else {
        isStop.value = false
        isStart.value = false
        player.value.level = maxLv
        player.value.maxCultivation = Math.floor(100 * Math.pow(2, maxLv))
        texts.value.push('你当前的境界已修炼圆满, 需要转生后才能继续修炼')
      }
    }
  }
  // 发现的装备信息
  const openEquipmentInfo = item => {
    if (!victory.value) return
    ElMessageBox.confirm('', item.name, {
      center: true,
      message: `<div class="monsterinfo">
      <div class="monsterinfo-box">
        <p>类型: ${genre[item.type] ?? '未知'}</p>
        <p>境界: ${levelNames(item.level)}</p>
        <p>品质: ${levels[item.quality] ?? '未知'}</p>
        <p>气血: ${formatNumberToChineseUnit(item.health)}</p>
        <p>攻击: ${formatNumberToChineseUnit(item.attack)}</p>
        <p>防御: ${formatNumberToChineseUnit(item.defense)}</p>
        <p>闪避率: ${(item.dodge * 100).toFixed(2) ?? 0}%</p>
        <p>暴击率: ${(item.critical * 100).toFixed(2) ?? 0}%</p>
      </div>
    </div>`,
      showCancelButton: false,
      confirmButtonText: '确定',
      dangerouslyUseHTMLString: true
    }).catch(() => {})
  }
  // 收服灵宠
  const harvestPet = item => {
    isCaptureFailed.value = true
    // 成功几率
    const successRate = calculateCaptureRate()
    // 是否成功收服
    const isSuccess = successRate >= getRandomInt(1, 100)
    // 如果成功收服
    if (isSuccess) {
      // 总背包容量大于灵宠背包容量就可以收服对方
      if (player.value.backpackCapacity > player.value.pets.length) {
        // 收服后的属性根据收服前的成功率算
        const newProperties = Math.floor((100 - successRate) * 0.5)
        // 攻击
        const attack = Math.floor(getRandomInt(50, 150) * newProperties)
        // 防御
        const defense = Math.floor(getRandomInt(1, 15) * newProperties)
        // 血量
        const health = Math.floor(getRandomInt(100, 500) * newProperties)
        // 闪避
        const dodge = parseFloat(getRandomFloatInRange(0.001, 0.01) * newProperties)
        // 暴击
        const critical = parseFloat(getRandomFloatInRange(0.001, 0.01) * newProperties)
        // 添加到灵宠背包里
        player.value.pets.push({
          id: Date.now(),
          lock: false,
          name: item.name,
          level: 1,
          score: equip.calculateEquipmentScore(dodge, attack, health, critical, defense),
          dodge,
          health,
          attack,
          defense,
          critical,
          // 初始数据
          initial: {
            dodge,
            health,
            attack,
            defense,
            critical,
            rootBone: newProperties
          },
          // 悟性
          rootBone: newProperties,
          // 好感度
          favorability: 0,
          // 转生
          reincarnation: 0
        })
        // 玩家灵宠成就
        const petAchievement = player.value.achievement.pet
        // 完成成就
        const checkAchievement = item => {
          const conditions = item.condition
          return (
            (conditions.health === 0 || conditions.health <= health) &&
            (conditions.attack === 0 || conditions.attack <= attack) &&
            (conditions.defense === 0 || conditions.defense <= defense) &&
            (conditions.dodge === 0 || conditions.dodge <= dodge.toFixed(2)) &&
            (conditions.critical === 0 || conditions.critical <= critical.toFixed(2))
          )
        }
        // 完成成就
        achievement.pet().forEach(item => {
          // 检查成就条件是否达成并且成就尚未完成
          if (checkAchievement(item) && !petAchievement.find(i => i.id === item.id)) {
            // 添加成就
            player.value.achievement.pet.push({ id: item.id })
            // 增加培养丹
            player.value.props.cultivateDan += item.award
            // 发送通知
            gameNotifys({ title: '获得成就提示', message: `恭喜你完成了${item.name}成就` })
          }
        })
        texts.value.push(`收服${item.name}成功`)
      } else {
        texts.value.push(`灵宠背包容量已满, 收服${item.name}失败, 转生可增加灵宠背包容量`)
      }
      // 恢复回合数
      guashaRounds.value = 10
      stopFight()
      // 如果没有收服
    } else {
      isCaptureFailed.value = true
      texts.value.push(`收服${item.name}失败`)
    }
  }
  // 计算收服灵宠成功概率
  const calculateCaptureRate = () => {
    // 基础100%几率
    const baseRate = 100
    // 每升一级减少的基础几率
    const decayFactor = 0.98
    // 根据等级计算实际几率
    let captureRate = baseRate * Math.pow(decayFactor, player.value.level)
    // 确保几率在 0% 到 100% 之间
    captureRate = Math.floor(Math.max(0, Math.min(100, captureRate)))
    return captureRate
  }
  const getRandomInt = (min, max) => {
    min = Math.ceil(min)
    max = Math.floor(max)
    return Math.floor(Math.random() * (max - min + 1)) + min
  }

  const getRandomFloatInRange = (min, max) => {
    return Math.random() * (max - min) + min
  }

  onUnmounted(() => {
    stopFight()
    // 移除键盘监听
    window.removeEventListener('keydown', operate)
  })

  onMounted(() => {
    if (monster.value.name) loading.value = false
    // 添加键盘监听
    window.addEventListener('keydown', operate)
  })
</script>

<style scoped>
  .actions .action {
    width: calc(33.333% - 10px);
    margin: 5px;
  }

  .shortcutKeys {
    color: rgba(169, 169, 169, 0.4);
    margin-left: 2px;
  }

  .cultivate.error {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 770px;
  }

  @media only screen and (max-width: 768px) {
    .shortcutKeys {
      display: none;
    }
  }
</style>
